package com.dek.ioc.context;

import static org.hamcrest.CoreMatchers.nullValue;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;

import com.dek.ioc.config.Bean;
import com.dek.ioc.config.Property;
import com.dek.ioc.factory.BeanFactory;
import com.dek.ioc.utils.BeanUtils;
import com.dek.ioc.utils.ConfigManager;

public class ClassPathXmlApplicationContext implements BeanFactory {
	
	private Map<String, Bean> config;
	
	private Map<String, Object> context = new HashMap<>();
	
	public ClassPathXmlApplicationContext(String path) {
		config = ConfigManager.getConfig(path);
		if (config != null) {
			for(Entry<String, Bean> en : config.entrySet()) {
				String beanName = en.getKey();
				Bean bean = en.getValue();
				// 避免多次创建
				Object existBean = context.get(beanName);
				if (existBean == null && "singleton".equals(bean.getScope())) {
					Object beanObj = createBean(bean);
					context.put(beanName, beanObj);
				}
			}
		}
	}

	private Object createBean(Bean bean) {
		Class clazz = null;
		try {
			clazz = Class.forName(bean.getClazz());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException("找不到" + bean.getClazz());
		}
		Object o = null;
		try {
			o = clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(bean.getClazz() + "找不到空参构造函数");
		}
		if (bean.getProperties() != null) {
			for(Property property : bean.getProperties()) {
				Method setMethod = BeanUtils.getSetMethod(o, property.getName());
				Object setParam = null;
				if (property.getValue() != null) {
					setParam = property.getValue();
				}
				if (property.getRef() != null) {
					// 先从容器中查找
					Object existBean = context.get(property.getRef());
					if (existBean == null) {
						// 递归调用
						existBean = createBean(config.get(property.getRef()));
						// 放入容器
						if ("singleton".equals(config.get(property.getRef()))) {
							context.put(property.getRef(), existBean);
						}
					}
					setParam = existBean;
				}
				try {
					setMethod.invoke(o, setParam);
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
					e.printStackTrace();
					throw new RuntimeException(bean.getClazz() + "的" + property.getName() + "没有对应set方法");
				}
			}
		}
		return o;
	}
	
	private Object createBean2(Bean bean) {
		Class clazz = null;
		try {
			clazz = Class.forName(bean.getClazz());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException("找不到" + bean.getClazz());
		}
		Object o = null;
		try {
			o = clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(bean.getClazz() + "找不到空参构造函数");
		}
		if (bean.getProperties() != null) {
			for(Property property : bean.getProperties()) {
				
				String name = property.getName();
				String value = property.getValue();
				String ref = property.getRef();
				
				Map<String, ? extends Object> properties;
				// 值类型属性
				if (value != null) {
					Map<String, String[]> param = new HashMap<>();
					param.put(name, new String[] {value});
					try {
						org.apache.commons.beanutils.BeanUtils.populate(bean, param);
					} catch (IllegalAccessException | InvocationTargetException e) {
						e.printStackTrace();
						throw new RuntimeException("");
					}
				}
				// bean类型属性
				if (property.getRef() != null) {
					// 先从容器中查找
					Method setMethod = BeanUtils.getSetMethod(o, property.getName());
					
					
					Object existBean = context.get(property.getRef());
					if (existBean == null) {
						// 递归调用
						existBean = createBean(config.get(property.getRef()));
						// 放入容器
						if ("singleton".equals(config.get(property.getRef()))) {
							context.put(property.getRef(), existBean);
						}
					}
					try {
						setMethod.invoke(o, existBean);
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
						throw new RuntimeException(bean.getClazz() + "的" + property.getName() + "没有对应set方法");
					}
				}
				
			}
		}
		return o;
	}
	
	@Override
	public Object getBean(String name) {
		// 如果scope为prototype， context就不会包含该bean
		Object bean = context.get(name);
		if (bean == null) {
			bean = createBean(config.get(name));
		}
		return bean;
	}

	@Override
	public <T> T getBean(Class<T> clazz) {
		// TODO Auto-generated method stub
		return null;
	}
	

	
}
